Skip to content

Fix non-converging generic parameter inference loop (A3)#216

Merged
ASDAlexander77 merged 1 commit into
mainfrom
fix/inference-loop-guard
Jul 12, 2026
Merged

Fix non-converging generic parameter inference loop (A3)#216
ASDAlexander77 merged 1 commit into
mainfrom
fix/inference-loop-guard

Conversation

@ASDAlexander77

Copy link
Copy Markdown
Owner

Summary

Root-causes and fixes A3 from docs/MLIRGen-refactoring-review.md — the // TODO: find out the issue behind the arbitrary +100 "loop detected." guard in resolveGenericParamsFromFunctionCall.

Two defects fed each other:

  1. Params without call operands were counted every round. Optional/multi-args params past callOpsCount did processed++ each iteration without being marked processed, so totalProcessed inflated by that count per round and could step right over the == termination check — spinning the loop into the +100 guard. They are now marked processed and counted exactly once.
  2. That double-counting was load-bearing. For signatures like the test suite's reduce2<T, V = T>(this: T[], func: (v: V, t: T) => V, initial?: V), the callback param can never resolve inside the loop — V only gets its value from the default zipping that runs after it — and only the inflated count let the loop terminate. With honest counting, a zero-progress round now breaks out of the loop instead of erroring immediately, letting the default zipping and the existing completeness check (typeParamsWithArgs.size() < typeParams.size() → the same "not all types could be inferred" message) decide whether inference actually failed.

Net effect: each param is counted at most once, the loop terminates by equality or by no-progress, and the +100 guard is now defensive-only (documented as such). One deliberate semantic refinement: a program whose type params are fully resolved despite an unresolvable-in-loop param now proceeds (previously it errored) — that is the reduce2 shape, which the old code only accepted by accident of the double-count.

Test plan

  • First run of the full suite caught exactly the load-bearing case (01lambdas failing in compile + JIT) and drove the two-part fix — the final design is validated against the real corpus, not just theory
  • Final run: 683/683 ctest tests passed (155 s)
  • Generic-inference smoke (apply2<T, R>(f, v, tag?)42) verified

🤖 Generated with Claude Code

Two defects fed each other in resolveGenericParamsFromFunctionCall:

- optional/multi-args params past the call operands were counted as
  progress every round without being marked processed, inflating
  totalProcessed past the == termination check - the origin of the
  "loop detected" +100 guard. They are now marked processed and
  counted once.
- that double-counting was also load-bearing: for signatures like
  reduce2<T, V = T>(..., initial?: V) a callback param typed by a
  defaulted type param can never resolve inside the loop (defaults zip
  after it), and only the inflated count let the loop exit. A
  no-progress round now breaks out instead of erroring, letting the
  default zipping and the existing completeness check decide.

The +100 guard is now defensive-only (each param counted at most once).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ASDAlexander77 ASDAlexander77 merged commit aaef434 into main Jul 12, 2026
2 checks passed
@ASDAlexander77 ASDAlexander77 deleted the fix/inference-loop-guard branch July 12, 2026 22:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant